package com.user.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.common.context.UserContextHolder;
import com.common.exception.GlobalException;
import com.common.exception.users.LoginException;
import com.common.exception.users.UsernamePasswordException;
import com.common.exception.users.UsersException;
import com.common.handler.RedisKeysHandler;
import com.common.rabbitmq.producer.core.MediaProducer;
import com.common.tool.EmailTool;
import com.user.authentication.LoginDetail;
import com.user.domain.dto.RegisterDto;
import com.user.domain.dto.UserDto;
import com.user.domain.params.SecurityParams;
import com.user.domain.params.UpdateUserParams;
import com.user.domain.pojo.*;
import com.user.domain.vo.CourseVo;
import com.user.domain.vo.UserInfo;
import com.user.domain.vo.UserPubInfo;
import com.user.domain.vo.UserVo;
import com.user.enums.LoginType;
import com.user.enums.UsersRoleContext;
import com.user.enums.UsersStatusEnum;
import com.user.enums.UsersTypeEnums;
import com.user.feign.CourseFeignClient;
import com.user.feign.MediaFeignClient;
import com.user.handler.LoginFactory;
import com.user.mapper.UserMapper;
import com.user.service.IRoleService;
import com.user.service.IUserFollowService;
import com.user.service.IUserRoleService;
import com.user.service.IUserService;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.connection.RedisZSetCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.Assert;

import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 小杰大人
 * @since 2025-02-17
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Resource(name = "myTransactionTemplate")
    TransactionTemplate transactionTemplate;
    private final MediaFeignClient mediaFeignClient;
    private final CourseFeignClient courseFeignClient;
    private final IUserRoleService iUserRoleService;
    private final IRoleService iRoleService;
    private final StringRedisTemplate stringRedisTemplate;
    @Resource(name = "MasterRedisTemplate")
    RedisTemplate<String, Object> masterRedisTemplate;
    private final  IUserFollowService iUserFollowService;
    private final  EmailTool emailTool;
    @Resource
    MediaProducer mediaProducer;
    private final LoginFactory loginFactory;
    private final PasswordEncoder passwordEncoder;
    // 邮箱校验正则
    private static final Pattern EMAIL_PATTERN = Pattern.compile("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$");
    // 手机号校验正则
    private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");

    @Override
    public void login(HttpServletRequest request, HttpServletResponse response, LoginDetail loginDetail) {
        Byte type = loginDetail.getType();
        try {
            if (type == 1) {
                loginFactory.login(request, response, loginDetail.getUsername(), loginDetail.getPassword(), LoginType.USERNAME_PASSWORD);
            } else if (type == 2) {
                loginFactory.login(request, response, loginDetail.getPhone(), loginDetail.getCodePhone(), LoginType.PHONE_CODE);
            } else {
                throw new LoginException("登录类型错误");
            }
        } catch (ServletException | IOException e) {
            throw new LoginException(e.getMessage());
        }
    }

    @Override
    public void logout(HttpServletRequest request, HttpServletResponse response) {
        stringRedisTemplate.delete(RedisKeysHandler.getTokenKey(UserContextHolder.getContext().getUsersId()));
    }

    @Override
    public boolean checkLogin(String username, String phone) {
        if (StrUtil.isEmptyIfStr(username) && StrUtil.isEmptyIfStr(phone)){
            throw new UsersException("请输入账号");
        }
        if (!StrUtil.isEmptyIfStr(username)){
            User user = baseMapper.querySelectByUsername(username);
            if (user == null){
                throw new UsersException(UsersException.USER_NULL);
            }
            return BooleanUtil.isTrue(stringRedisTemplate.hasKey(RedisKeysHandler.getTokenKey(user.getId())));
        }
        if (!StrUtil.isEmptyIfStr(phone)){
            User user = baseMapper.querySelectByPhone(phone);
            if (user == null){
                throw new UsersException(UsersException.USER_NULL);
            }
            return BooleanUtil.isTrue(stringRedisTemplate.hasKey(RedisKeysHandler.getTokenKey(user.getId())));
        }
        return false;
    }

    @Override
    public User getDetailById(Long usersId) {
        User user = this.getById(usersId);
        user.setPassword(null);
        // 手机号进行敏感操作
        String email = user.getEmail();
        String maskEmail = maskEmail(email);
        user.setEmail(maskEmail);
        // 邮箱进行敏感操作
        String phone = user.getPhone();
        String maskPhone = maskPhone(phone);
        user.setPhone(maskPhone);
        return user;
    }

    @Override
    @Transactional
    public void updateUserDetail(UpdateUserParams userParams) {
        User user = new User();
        BeanUtils.copyProperties(userParams, user);
        user.setId(UserContextHolder.getContext().getUsersId());
        transactionTemplate.execute(status -> this.updateById(user));
    }

    @Override
    public void updatePhone(SecurityParams securityParams) {
        // 1: 校验手机号格式
        if (!validatePhone(securityParams.getPrincipal())) {
            throw new UsersException("手机号格式有误");
        }
        // 2: 校验验证码信息
        String code = stringRedisTemplate.opsForValue().get(RedisKeysHandler.getValidatePhoneCodeKey(securityParams.getPrincipal()));
        validateCode(securityParams.getCode(), code);
        // 3: 判断是否已经被绑定
        long count = this.count(new LambdaQueryWrapper<User>().eq(User::getPhone, securityParams.getPrincipal()));
        if (count > 0) {
            throw new UsersException("手机号已被绑定");
        }
        // 4: 更新手机号
        User user = new User();
        user.setId(UserContextHolder.getContext().getUsersId());
        user.setPhone(securityParams.getPrincipal());
        transactionTemplate.execute(status -> this.updateById(user));
    }


    @Override
    public void updateEmail(SecurityParams securityParams) {
        // 1：校验邮箱格式
        if (!validateEmail(securityParams.getPrincipal())) {
            throw new UsersException("邮箱格式有误");
        }
        // 2: 校验验证码信息
        String code = stringRedisTemplate.opsForValue().get(RedisKeysHandler.getValidateEmailCodeKey(securityParams.getPrincipal()));
        validateCode(securityParams.getCode(), code);
        // 3: 判断是否已经被绑定
        long count = this.count(new LambdaQueryWrapper<User>().eq(User::getEmail, securityParams.getPrincipal()));
        if (count > 0) {
            throw new UsersException("邮箱已被绑定");
        }
        // 4: 更新邮箱
        User user = new User();
        user.setId(UserContextHolder.getContext().getUsersId());
        user.setEmail(securityParams.getPrincipal());
        transactionTemplate.execute(status -> this.updateById(user));
    }


    /**
     * 根据用户id获取用户基本信息
     *
     * @param id
     * @return
     */
    public UserInfo getUserInfoById(Long id) {
        User user = this.getById(id);
        Assert.notNull(user, "用户不存在");
        return UserToInfo(user);
    }

    @Override
    public boolean updateUserAvatar(Long id, Long mediaId) {
        User user = new User();
        user.setId(id);
        user.setMediaId(mediaId);
        return this.updateById(user);
    }

    @Override
    public UserVo getUserVo(Long id) {
        Assert.notNull(id, "用户id不能为空");
        UserVo userVo = new UserVo();
        User user = this.getById(id);
        user.setPassword(null);
        Assert.notNull(user, "用户不存在");
        BeanUtils.copyProperties(user, userVo);
        List<Role> roles = baseMapper.querySelectRoleByUsername(user.getUsername());
        userVo.setRoleList(roles);
        return userVo;
    }

    @Override
    @Transactional
    public void addUsers(UserDto userDto) {
        User user = new User();
        BeanUtils.copyProperties(userDto, user);
        String username = user.getUsername();  // 校验用户名是否重复
        User usernameUser = this.getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username));
        Assert.isNull(usernameUser, "用户名已存在");
        String phone = user.getPhone();    // 校验手机号是否重复
        if (validatePhone(phone)) {
            User phoneUser = this.getOne(new LambdaQueryWrapper<User>().eq(User::getPhone, phone));
            Assert.isNull(phoneUser, "手机号已存在");
        }
        String email = user.getEmail();    // 校验邮箱是否重复
        if (!StrUtil.isEmpty(email) && validateEmail(email)) {
            User emailUser = this.getOne(new LambdaQueryWrapper<User>().eq(User::getEmail, email));
            Assert.isNull(emailUser, "邮箱已存在");
        }
        String password = user.getPassword();
//        user.setPassword(passwordEncoder.encode(password));    // 密码加密存储
        this.save(user);   // 新增用户
        List<Long> roleList = userDto.getRoleList();
        // 添加用户角色关联
        insertUserRole(user.getId(), roleList);
    }

    @Override
    @Transactional
    public void updateUsers(UserDto userDto) {
        // 原始数据
        User user = this.getById(userDto.getId());
        // 校验修改后的用户名是否重复
        String username = userDto.getUsername();    // 修改后的用户名
        if (!user.getUsername().equals(username)) { // 如果修改后的用户名与原始用户名不同，则校验用户名是否重复
            User usernameUser = this.getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username));
            Assert.isNull(usernameUser, "用户名已存在");
        }
        BeanUtils.copyProperties(userDto, user);
        this.updateById(user);
        // 删除用户与角色的关联信息
        iUserRoleService.remove(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, user.getId()));
        // 重建用户与角色的关联信息
        insertUserRole(user.getId(), userDto.getRoleList());
        // 清空当前用户的登入权限信息
        stringRedisTemplate.delete(RedisKeysHandler.getUserAuthorityKey(user.getUsername()));
        // 清空当前用户的token信息
        stringRedisTemplate.delete(RedisKeysHandler.getTokenKey(user.getId()));
    }

    @Override
    @Transactional
    public void removeUsers(List<Long> ids) {
        List<User> users = this.listByIds(ids);
        for (User user : users) {
            // 删除用户与角色的关系
            iUserRoleService.remove(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, user.getId()));
            // 删除用户头像信息
            mediaProducer.mediaRemoveById(user.getId());
            // 删除redis中的认证状态
            stringRedisTemplate.delete(RedisKeysHandler.getUserAuthorityKey(user.getUsername()));
            // 删除redis中的token信息
            stringRedisTemplate.delete(RedisKeysHandler.getTokenKey(user.getId()));
        }
        // 删除用户信息
        this.removeBatchByIds(ids);
    }

    @Override
    @Transactional
    public void registerUser(RegisterDto registerDto) {
        String password = registerDto.getPassword();
        String repassword = registerDto.getRepassword();
        if (!Objects.equals(password, repassword)) {
            throw new UsernamePasswordException("两次密码不一致");
        }
        User user = new User();
        user.setUsername(registerDto.getUsername());
        user.setPassword(passwordEncoder.encode(password));
        user.setName(registerDto.getName());
        user.setStatus(UsersStatusEnum.NORMAL.getCode());
        user.setType(UsersTypeEnums.USER.getCode());
        this.save(user);

        // 添加用户角色关联
        UserRole userRole = new UserRole();
        userRole.setUserId(user.getId());
        Role defaultRole = iRoleService.getOne(new LambdaQueryWrapper<Role>().eq(Role::getName, UsersRoleContext.DEFAULT));
        userRole.setRoleId(defaultRole.getId());
        iUserRoleService.save(userRole);
    }

    @Override
    public void sendSmsPhoneCodeByLogin(String phone) {
        if (StrUtil.isEmptyIfStr(phone)) {
            throw new LoginException("手机号不能为空");
        }
        if (!validatePhone(phone)) {
            throw new LoginException("手机号格式不正确");
        }
        String code = RandomUtil.randomNumbers(6);
        stringRedisTemplate.opsForValue().set(RedisKeysHandler.getLoginPhoneCodeKey(phone), code, 5, TimeUnit.MINUTES);    // 存储验证码到redis中
        // TODO: 2025/4/24 阿里云短信模板发送即可
    }

    @Override
    public void sendSmsEmailCodeByValidate(String email) {
        // 1: 数据格式校验
        if (StrUtil.isEmptyIfStr(email)) {
            throw new LoginException("邮箱号不能为空");
        }
        if (!validateEmail(email)) {
            throw new LoginException("邮箱号格式不正确");
        }
        // 2: 生成校验验证码
        String code = RandomUtil.randomNumbers(6);
        // 2.1: 获取目标用户的用户名与姓名
        User user = this.getById(UserContextHolder.getContext().getUsersId());
        // 3: 发送验证码
        CompletableFuture.runAsync(() ->
                emailTool.sendEmailHTML("E选课", "<h2>尊敬的 " + user.getUsername() + "(" + user.getName() + ")" + "：</h2>\n" +
                        "    <p class=\"message\" style=\"color: #666;\">您的账号正在执行敏感操作：</p>\n" +
                        "    <div class=\"code\" style=\"font-size: 24px; color: #333; margin: 20px 0;\">" + code + "</div>\n" +
                        "    <p class=\"message\" style=\"color: #666;\">验证码有效期为5分钟。</p>\n" +
                        "    <p class=\"message\" style=\"color: #666;\">如果这不是您的操作，请忽略此邮件。</p>\n", email));
        // 4：验证码存储到Redis中
        stringRedisTemplate.opsForValue().set(RedisKeysHandler.getValidateEmailCodeKey(email), code, 5, TimeUnit.MINUTES);
    }

    @Override
    public void sendSmsPhoneCodeByValidate(String phone) {
        // 1: 数据格式校验
        if (StrUtil.isEmptyIfStr(phone)) {
            throw new LoginException("手机号不能为空");
        }
        if (!validatePhone(phone)) {
            throw new LoginException("手机号格式不正确");
        }
        // 2: 生成校验验证码
        String code = RandomUtil.randomNumbers(6);
        // TODO: 2025/4/24 阿里云短信模板发送即可
        // 4：验证码存储到Redis中
        stringRedisTemplate.opsForValue().set(RedisKeysHandler.getValidatePhoneCodeKey(phone), code, 5, TimeUnit.MINUTES);
    }

    @Override
    public User querySelectByUniqueIdentification(Object uniqueIdentification) {
        Assert.notNull(uniqueIdentification, "用户唯一标识符不能为空");
        User user;
        if (NumberUtil.isNumber(uniqueIdentification.toString())) {
            user = baseMapper.querySelectById(Long.valueOf(uniqueIdentification.toString()));
        } else {
            user = baseMapper.querySelectByUsername(uniqueIdentification.toString());
        }
        if (user == null) {
            throw new IllegalArgumentException("用户唯一标识符类型错误");
        }
        return user;
    }

    @NotNull
    public UserInfo UserToInfo(User user) {
        UserInfo userInfo = new UserInfo();
        BeanUtils.copyProperties(user, userInfo);
        userInfo.setName(user.getInstitution() + " " + user.getName());
        Long mediaId = user.getMediaId();
        if (mediaId != null) {
            Media media = mediaFeignClient.querySelectMediaById(mediaId).getData();
            Optional.ofNullable(media).ifPresent(media1 -> userInfo.setImage(media1.getUrl()));
        }
        return userInfo;
    }

    @Override
    public Boolean isFollow(Long followUserId) {
        return iUserFollowService.exists(new LambdaQueryWrapper<UserFollow>()
                .eq(UserFollow::getUserId, UserContextHolder.getContext().getUsersId())
                .eq(UserFollow::getFollowUserId, followUserId));
    }

    @Override
    public void follow(Long followUserId, Boolean isFollow) {
        Long usersId = UserContextHolder.getContext().getUsersId();

        if (isFollow) {
            // 添加关注
            UserFollow userFollow = new UserFollow();
            userFollow.setUserId(usersId);
            userFollow.setFollowUserId(followUserId);
            boolean save = iUserFollowService.save(userFollow);
            if (save) {
                // Redis: 当前用户新增关注列表
                // Redis: 被关注用户新增粉丝列表
                // 使用Pipeline 管理联合处理
                RedisCallback<Object> redisCallback = connection -> {
                    // 操作SortedSet
                    RedisZSetCommands redisZSetCommands = connection.zSetCommands();
                    // 当前用户新增关注列表
                    redisZSetCommands.zAdd(RedisKeysHandler.getUserFollowListKey(usersId).getBytes(), System.currentTimeMillis(), followUserId.toString().getBytes());
                    // 被关注用户新增粉丝列表
                    redisZSetCommands.zAdd(RedisKeysHandler.getUserFansListKey(followUserId).getBytes(), System.currentTimeMillis(), usersId.toString().getBytes());
                    return null;
                };
                stringRedisTemplate.executePipelined(redisCallback);
            }
        } else {
            boolean remove = iUserFollowService.remove(new LambdaQueryWrapper<UserFollow>()
                    .eq(UserFollow::getUserId, usersId)
                    .eq(UserFollow::getFollowUserId, followUserId));
            if (remove) {
                // Redis: 当前用户取消关注
                // Redis: 被关注用户取消粉丝
                // 使用Pipeline 管理联合处理
                RedisCallback<Object> redisCallback = connection -> {
                    // 操作SortedSet
                    RedisZSetCommands redisZSetCommands = connection.zSetCommands();
                    // 当前用户取消关注
                    redisZSetCommands.zRem(RedisKeysHandler.getUserFollowListKey(usersId).getBytes(), followUserId.toString().getBytes());
                    // 被关注用户取消粉丝
                    redisZSetCommands.zRem(RedisKeysHandler.getUserFansListKey(followUserId).getBytes(), usersId.toString().getBytes());
                    return null;
                };
                stringRedisTemplate.executePipelined(redisCallback);
            }
        }
    }

    @Override
    public List<UserInfo> getUserFollowList(Integer module, Integer sorted, String query) {
        // 1：获取用户id
        Long usersId = UserContextHolder.getContext().getUsersId();
        ZSetOperations<String, String> zSet = stringRedisTemplate.opsForZSet();
        Set<String> range;
        if (module == 1) {
            // 2: 判断 - 获取我关注的人
            if (sorted == 1) {
                // 升序
                range = zSet.range(RedisKeysHandler.getUserFollowListKey(usersId), 0, -1);
            } else {
                // 降序
                range = zSet.reverseRange(RedisKeysHandler.getUserFollowListKey(usersId), 0, -1);
            }
        } else {
            // 3: 判断 - 获取关注我的人
            if (sorted == 1) {
                // 升序
                range = zSet.range(RedisKeysHandler.getUserFansListKey(usersId), 0, -1);
            } else {
                // 降序
                range = zSet.reverseRange(RedisKeysHandler.getUserFansListKey(usersId), 0, -1);
            }
        }
        if (range == null || range.isEmpty()) {
            return Collections.emptyList();
        }
        return range.stream().map(id -> {
            User user = this.getById(id);
            return UserToInfo(user);
        }).filter(userInfo -> {
            if ("all".equals(query)) {
                return true;
            } else if ("teacher".equals(query)) {
                return userInfo.getType() == 0 || userInfo.getType() == 2;
            } else if ("student".equals(query)) {
                return userInfo.getType() == 1;
            } else {
                throw new GlobalException("非法的query");
            }
        }).toList();
    }

    @Override
    public UserPubInfo getUserPublicInfo(Long id) {
        // 1: 得到当前访问用户Id
        Long usersId = UserContextHolder.getContext().getUsersId();
        // 2: 获取目标用户的基本信息
        User user = this.getById(id);
        if (user == null) {
            throw new GlobalException("用户不存在");
        }
        UserInfo userInfo = this.UserToInfo(user);
        // 3: 获取目标用户的发布的课程信息
        List<CourseVo> courses = courseFeignClient.getCourseListPublishByUsername(userInfo.getUsername()).getData();
        // 4: 获取目标用户的与当前登入用户的相同关注
        List<UserInfo> userInfos;
        List<Long> ids = evalScriptUnionFollow(RedisKeysHandler.getUserFollowListKey(usersId), RedisKeysHandler.getUserFollowListKey(id));
        if (ids == null || ids.isEmpty()) {
            userInfos = Collections.emptyList();
        } else {
            List<User> userList = this.listByIds(ids);
            userInfos = userList.stream().map(this::UserToInfo).toList();
        }
        // 5: 获取目标用户的粉丝数量
        Long fansSum = stringRedisTemplate.opsForZSet().zCard(RedisKeysHandler.getUserFansListKey(id));
        // 6: 获取目标用户的关注数量
        Long followSum = stringRedisTemplate.opsForZSet().zCard(RedisKeysHandler.getUserFollowListKey(id));
        UserPubInfo userPubInfo = new UserPubInfo();
        BeanUtils.copyProperties(userInfo, userPubInfo);
        userPubInfo.setCourses(courses);
        userPubInfo.setFollowList(userInfos);
        userPubInfo.setFansSum(fansSum);
        userPubInfo.setFollowSum(followSum);
        return userPubInfo;
    }

    @Override
    public Map<Long, UserInfo> querySelectUserListByIds(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            return Collections.emptyMap();
        }
        List<User> users = this.listByIds(ids);
        if (users == null || users.isEmpty()) {
            return Collections.emptyMap();
        }
        // 获取用户的头像文件
        Set<Long> mediaIds = users.stream().map(User::getMediaId).filter(Objects::nonNull).collect(Collectors.toSet());
        Map<Long, Media> mediaMap = mediaFeignClient.querySelectMediaByIds(new ArrayList<>(mediaIds)).getData();
        // 将用户列表转换为Map，键为用户ID，值为用户对象
        Map<Long, UserInfo> map = new HashMap<>(users.size());
        for (User user : users) {
            UserInfo userInfo = BeanUtil.toBean(user, UserInfo.class);
            userInfo.setName(user.getInstitution() + " " + user.getName());
            Media media = mediaMap.get(user.getMediaId());
            if (media != null) {
                userInfo.setImage(media.getUrl());
            }
            map.put(user.getId(), userInfo);
        }
        return map;
    }

    @Override
    public List<String> getUserRoleNameList(Long id) {
        return baseMapper.querySelectRoleById(id).stream().map(Role::getName).toList();
    }

    @Override
    public Long getUserFansCount(Long userId) {
        return iUserFollowService.getFollowCount(userId);
    }

    @Override
    public User querySelectByUsername(String username) {
        return baseMapper.querySelectByUsername(username);
    }

    private void insertUserRole(Long usersId, List<Long> roleList) {
        List<UserRole> list = roleList.stream().map(roleId -> {
            UserRole userRole = new UserRole();
            userRole.setUserId(usersId);
            userRole.setRoleId(roleId);
            return userRole;
        }).toList();
        iUserRoleService.saveBatch(list);   // 新增用户与角色的关联信息
    }


    private static String maskPhone(String phone) {
        if (phone == null || phone.length() < 7) {
            return phone; // 如果手机号不合法，直接返回原值
        }
        // 保留前3位和后4位，中间用 **** 替换
        return phone.substring(0, 3) + "****" + phone.substring(phone.length() - 4);
    }

    private static String maskEmail(String email) {
        if (email == null || !email.contains("@")) {
            return email; // 如果邮箱不合法，直接返回原值
        }
        // 分割前缀和域名
        String[] parts = email.split("@");
        String prefix = parts[0]; // 前缀部分
        String domain = parts[1]; // 域名部分

        // 保留前缀的前3位，后面用 **** 替换
        if (prefix.length() > 3) {
            prefix = prefix.substring(0, 3) + "****";
        } else {
            prefix = "****"; // 如果前缀长度不足3位，全部替换
        }
        return prefix + "@" + domain;
    }

    public static boolean validateEmail(String email) {
        if (email == null) {
            return false;
        }
        return EMAIL_PATTERN.matcher(email).matches();
    }

    public static boolean validatePhone(String phone) {
        if (phone == null) {
            return false;
        }
        return PHONE_PATTERN.matcher(phone).matches();
    }

    private static void validateCode(String originCode, String targetCode) {
        if (Objects.isNull(originCode)) {
            throw new UsersException("验证码已过期，请重新获取");
        }
        if (!Objects.equals(targetCode, originCode)) {
            throw new UsersException("验证码错误，请重试");
        }
    }

    private List<Long> evalScriptUnionFollow(String Key1, String Key2) {
        ClassPathResource classPathResource = new ClassPathResource("/script/UnionFollow.lua");
        DefaultRedisScript<List> defaultRedisScript = new DefaultRedisScript<>();
        defaultRedisScript.setLocation(classPathResource);  // 脚本资源地址
        defaultRedisScript.setResultType(List.class);    // 指定脚本执行结果
        List<String> keys = Arrays.asList(Key1, Key2);  // 脚本执行需要的key
        List<Object> result = masterRedisTemplate.execute(defaultRedisScript, keys);
        if (result == null || result.isEmpty()) {
            return Collections.emptyList();
        }
        return result.stream().map(id -> Long.parseLong(id.toString())).toList();
    }

}
